package utils.reflection;

import testfile.TestClass;
import utils.object.UtilValidate;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.*;
import java.net.URL;
import java.util.*;

/**
 * 反射工具类
 *
 * @author Chen Yuan
 * @create 2021-05-07  10:48
 */
public class ReflectionUtils {
	// 包名
	private static final String PACKAGE_NAME = "com.demo.entity";
	public static final char UNDERLINE = '_';

	/**
	 * 通过反射获取实体类中的字段及其中文注释
	 * 只会获取配置了 @ColumnExplain 注解的字段
	 *
	 * @param className 实体类名
	 * @return 封装的字段对象列表
	 * @throws ClassNotFoundException
	 */
	public static ArrayList<Object> getColumnAndExplainList(String className) throws ClassNotFoundException {
		ArrayList<Object> columnList = new ArrayList<>();
		Class<?> aClass = Class.forName(PACKAGE_NAME + className);
		Field[] fields = aClass.getDeclaredFields();
		for (Field field : fields) {
			//TableField tableField = field.getAnnotation(TableField.class);
			String fieldName = field.getName();
			ColumnExplain columnExplain = field.getAnnotation(ColumnExplain.class);
			if (UtilValidate.isNotEmpty(fieldName) &&
					UtilValidate.isNotEmpty(field) &&
					UtilValidate.isNotEmpty(columnExplain) &&
					UtilValidate.isNotEmpty(columnExplain.value())) {
				Object columnDTO = new Object();
				columnList.add(columnDTO);
			}
		}
		return columnList;
	}

	/**
	 * 通过反射执行 Getter
	 *
	 * @param fieldName   字段名称
	 * @param classObject 对象
	 * @return 字段值
	 */
	public static Object getFieldValueByName(String fieldName, Object classObject) {
		Object invoke = null;
		try {
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getter = "get" + firstLetter + fieldName.substring(1);
			Method method = classObject.getClass().getMethod(getter);
			invoke = method.invoke(classObject);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return invoke;
	}

	/**
	 * 驼峰格式字符串转换为下划线格式字符串
	 *
	 * @param param 驼峰格式字符串
	 * @return 下划线格式字符串
	 */
	public static String camelToUnderline(String param) {
		if (param == null || "".equals(param.trim())) {
			return "";
		}
		int len = param.length();
		StringBuilder sb = new StringBuilder(len);
		for (int i = 0; i < len; i++) {
			char c = param.charAt(i);
			if (Character.isUpperCase(c)) {
				sb.append(UNDERLINE);
				sb.append(Character.toLowerCase(c));
			} else {
				sb.append(c);
			}
		}
		return sb.toString();
	}


	/**
	 * 获取所有接口的实现类
	 *
	 * @return
	 */
	public static List<Class> getAllInterfaceAchieveClass(Class clazz) {
		ArrayList<Class> list = new ArrayList<>();
		//判断是否是接口
		if (clazz.isInterface()) {
			try {
				ArrayList<Class> allClass = getAllClassByPath(clazz.getPackage().getName());
				/**
				 * 循环判断路径下的所有类是否实现了指定的接口
				 * 并且排除接口类自己
				 */
				for (int i = 0; i < allClass.size(); i++) {

					//排除抽象类
					if (Modifier.isAbstract(allClass.get(i).getModifiers())) {
						continue;
					}
					//判断是不是同一个接口
					if (clazz.isAssignableFrom(allClass.get(i))) {
						if (!clazz.equals(allClass.get(i))) {
							list.add(allClass.get(i));
						}
					}
				}
			} catch (Exception e) {
				System.out.println("出现异常");
			}
		}
		return list;
	}


	/**
	 * 从指定路径下获取所有类
	 *
	 * @return
	 */
	public static ArrayList<Class> getAllClassByPath(String packagename) {
		ArrayList<Class> list = new ArrayList<>();
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		String path = packagename.replace('.', '/');
		try {
			ArrayList<File> fileList = new ArrayList<>();
			Enumeration<URL> enumeration = classLoader.getResources(path);
			while (enumeration.hasMoreElements()) {
				URL url = enumeration.nextElement();
				fileList.add(new File(url.getFile()));
			}
			for (int i = 0; i < fileList.size(); i++) {
				list.addAll(findClass(fileList.get(i), packagename));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return list;
	}

	/**
	 * 如果file是文件夹，则递归调用findClass方法，或者文件夹下的类
	 * 如果file本身是类文件，则加入list中进行保存，并返回
	 *
	 * @param file
	 * @param packagename
	 * @return
	 */
	private static ArrayList<Class> findClass(File file, String packagename) {
		ArrayList<Class> list = new ArrayList<>();
		if (!file.exists()) {
			return list;
		}
		File[] files = file.listFiles();
		for (File file2 : files) {
			if (file2.isDirectory()) {
				assert !file2.getName().contains(".");//添加断言用于判断
				ArrayList<Class> arrayList = findClass(file2, packagename + "." + file2.getName());
				list.addAll(arrayList);
			} else if (file2.getName().endsWith(".class")) {
				try {
					//保存的类文件不需要后缀.class
					list.add(Class.forName(packagename + '.' + file2.getName().substring(0,
							file2.getName().length() - 6)));
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		}
		return list;
	}

	public static void main(String[] args) {
		List<Class> classList = ReflectionUtils.getAllInterfaceAchieveClass(TestClass.class);
		System.out.println(classList);

		try {
			for (Class clazz : classList) {
				((TestClass) clazz.newInstance()).say();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
